﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using OpenRasta.IO;
using umbraco.BusinessLogic;
using umbraco.BusinessLogic.Utils;
using uREST.Core;
using uREST.CMS.Services;
using umbraco.cms.businesslogic.media;
using uREST.Core.Extensions;

namespace uREST.CMS.MediaFactories
{
    public class MediaFactory
    {
        private static readonly List<IMediaFactory> MediaFactories = new List<IMediaFactory>();

        static MediaFactory()
        {
            RegisterMediaFactories();
        }

        private static void RegisterMediaFactories()
        {
            var types = TypeFinder.FindClassesOfType<IMediaFactory>();

            foreach (var t in types)
            {
                IMediaFactory typeInstance = null;

                try
                {
                    if (t.IsVisible)
                    {
                        typeInstance = Activator.CreateInstance(t) as IMediaFactory;
                    }
                }
                catch { }

                if (typeInstance != null)
                {
                    try
                    {
                        MediaFactories.Add(typeInstance);
                    }
                    catch (Exception ee)
                    {
                        Log.Add(LogTypes.Error, -1, "Can't import MediaFactory '" + t.FullName + "': " + ee);
                    }
                }
            }

            MediaFactories.Sort((f1, f2) => f1.Priority.CompareTo(f2.Priority));
        }

        public static IMediaFactoryCreator GetMediaFactoryCreator(int parentId, UploadedFile uploadedFile, User user)
        {
            var ext = Path.GetExtension(uploadedFile.FileName);
            if (ext == null)
                return null;

            var factories = MediaFactories.Where(mf => mf.Extensions.Contains(ext.TrimStart('.'))).ToList();

            if (factories.Count == 0)
                factories = MediaFactories.Where(mf => mf.Extensions.Contains("*")).ToList();

            if (factories.Count > 0)
                return factories.Select(factory => factory as IMediaFactoryCreator).FirstOrDefault(typeInstance => typeInstance != null && typeInstance.CanCreateMedia(parentId, uploadedFile, user));

            return null;
        }

        public static IMediaFactoryUpdater GetMediaFactoryUpdater(int id, UploadedFile uploadedFile, User user)
        {
            Media media = null;

            try
            {
                media = new Media(id);
            }
            catch
            { }

            if (media == null)
                return null;

            var alias = media.ContentType.Alias;

            var ext = Path.GetExtension(uploadedFile.FileName);
            if (ext == null)
                return null;

            var factories = MediaFactories.Where(mf => mf.Extensions.Contains(ext.TrimStart('.'))).ToList();

            if (factories.Count == 0)
                factories = MediaFactories.Where(mf => mf.Extensions.Contains("*")).ToList();

            if (factories.Count > 0)
                return factories.Select(factory => factory as IMediaFactoryUpdater).FirstOrDefault(typeInstance => typeInstance != null && typeInstance.CanUpdateMedia(id, uploadedFile, user));

            return null;
        }
    }

    #region Helper Entities

    public class UploadedFile
    {
        public string FileName { get; set; }
        public string ContentType { get; set; }
        public int ContentLength { get; set; }
        public Stream InputStream { get; set; }

        public UploadedFile(IFile file)
        {
            FileName = file.FileName;
            ContentType = file.ContentType.ToString();
            ContentLength = (int)file.Length;
            InputStream = file.OpenStream();
        }

        public void SaveAs(string filename)
        {
            var s = new FileStream(filename, FileMode.Create);
            try
            {
                if (InputStream.CanSeek)
                    InputStream.Seek(0, SeekOrigin.Begin);
                InputStream.WriteTo(s);
                s.Flush();
            }
            finally
            {
                s.Close();
            }
        }
    }

    #endregion
}
